package com.liuwei.spring.cloud.junit.lixiang;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.liuwei.spring.cloud.biz.repository.db.entity.LiFeignChain;
import com.liuwei.spring.cloud.biz.repository.db.mapper.LiFeignChainMapper;
import com.liuwei.spring.cloud.biz.service.LiLogService;
import com.liuwei.spring.cloud.common.utils.Jackson;
import com.liuwei.spring.cloud.common.utils.StringPool;
import com.liuwei.spring.cloud.framework.spring.ApplicationHelper;
import com.liuwei.spring.cloud.junit.BaseJunit;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @author : com.liuwei.spring.junit.lixiang.LiLogsJunit
 * @version V1.0
 * @date: 2024/4/30 2:01 PM
 * @Description: TODO
 */
@Slf4j
public class LiLogsJunit extends BaseJunit {

    @Resource
    LiFeignChainMapper iLiFeignChainMapper;

    @Resource
    LiLogService iLiLogService;

    @Test
    @Transactional
    @Rollback(false)
    public void updateBatchById() throws InterruptedException {
        LiFeignChain chain = new LiFeignChain();
        chain.setEnv("prod");
        chain.setCluster("cnbj01");
        chain.setProvider("factory-dsc-searcher-api");
        chain.setConsumer("factory-dsc-searcher-api");
        chain.setTime("2024-04-29 19:41:47.512");
        chain.setUri("/v2/dsc/logistics/area-sap/search");
        int db = iLiFeignChainMapper.insert(chain);
        log.info("DB Result:{}",db);
    }

    @Test
    @Transactional
    @Rollback(false)
    public void dealLogsByDir() throws InterruptedException {
        List<String> contains = Arrays.asList(
                "prod-cnbjfa01-factory-wcs-dispatcher",

//                "prod-cnhb01-factory-dsc-searcher-api",
//                "prod-cnbjfa01-factory-dsc-searcher-api",
//                "prod-changzhou-factory-dsc-searcher-api",
//                "prod-changzhou02-factory-dsc-searcher-api",
//
//                "prod-cnhb01-factory-dsc-logistics-searcher",
//                "prod-cnbjfa01-factory-dsc-logistics-searcher",
//                "prod-changzhou-factory-dsc-logistics-searcher",
//                "prod-changzhou02-factory-dsc-logistics-searcher",
                ""
                );
        String baseDirPath = "/Users/liuwei19/Desktop/li-logs/";
        String env = "prod";
        String suffix = ".log";
        File baseDir = new File(baseDirPath);
        List<File> allLogs = getChildrenFiles(baseDir,suffix);
        if(CollectionUtils.isEmpty(allLogs)){
            log.info("Dir:{} 未找到 log 文件");
            return;
        }
        CountDownLatch countDownLatch = new CountDownLatch(allLogs.size());
        File[] providers = baseDir.listFiles();
        log.info("providers:{}", Jackson.toJSONString(providers));
        Arrays.asList(providers).forEach(x->{
            if(x.isDirectory()){
                String provider = x.getName();
                File[] clusters = x.listFiles();
                Arrays.asList(clusters).forEach(y->{
                    if(y.isDirectory()){
                        String env_cluster = y.getName();
                        String cluster = StringUtils.replace(env_cluster,env+"-","");
                        List<File> logs = getChildrenFiles(y,suffix);
                        CollectionUtils.emptyIfNull(logs).forEach(z->{
                            try {
                                log.info("Env:{} Cluster:{} Provider:{} Log File:{}",env,cluster,provider,z.getAbsolutePath());
                                String application = StrUtil.format("{}-{}-{}",env,cluster,provider);
                                if(!contains.contains(application)){
                                    log.info("Logs 文件忽略执行");
                                    countDownLatch.countDown();
                                }else{
                                    java.lang.String threadPoolName = "CompletableFuturePool";
                                    Executor executor = (Executor) ApplicationHelper.getApplicationContext().getBean(threadPoolName);
                                    CompletableFuture.runAsync(()->{
                                        iLiLogService.syncFileLog(env,cluster,provider,z.getAbsolutePath());
                                        countDownLatch.countDown();
                                    },executor);
                                }
                            } catch (Exception e) {
                                log.error(e.getMessage());
                                countDownLatch.countDown();
                            }
                        });
                    }
                });
            }
        });
        countDownLatch.await();
    }

    private List<File> getChildrenFiles(File dir,String suffix){
        List<File> allFiles = getAllFiles(dir);
        return CollectionUtils.emptyIfNull(allFiles).stream().filter(x->{
            return StringUtils.endsWithIgnoreCase(x.getName(),suffix);
        }).collect(Collectors.toList());
    }

    public List<File> getAllFiles(File directory) {
        List<File> fileList = new ArrayList<>();
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    fileList.addAll(getAllFiles(file));
                } else {
                    fileList.add(file);
                }
            }
        }
        return fileList;
    }


    public static void main(String[] args) throws Exception {
        String query =
                """
                {env="prod", app="factory-dsc-logistics-searcher", pod_ip=~".*"} |= "feign-call"
                """;
        String source = """
                %7Benv%3D%22prod%22%2C%20app%3D%22factory-dsc-logistics-searcher%22%2C%20pod_ip%3D~%22.*%22%7D%20%7C%3D%20%22feign-call%22
                """;
        System.out.println(URLEncoder.encode(query,Charset.defaultCharset()));
        Long start = DateUtil.beginOfDay(DateUtil.date()).getTime();
        int minutes = 30;
        Long end = start - minutes*60 * 1000;
        int times = 30*24*60/minutes;
        //times = 1;
        for (int i =0;i<=times;i++){
            try {
                String result = search("prod","factory-dsc-logistics-searcher","feign-call",String.valueOf(start*1000*1000),String.valueOf(end*1000*1000));
                dealLogs(result);
                Thread.sleep(1000);
            } catch (Exception e) {
                log.info(e.getMessage(),e);
            }
            // 重试时间间隔
            start = end;
            end = start - minutes*60 * 1000;
        }
    }

    private static void dealLogs(String result){
        List<String> lines = new ArrayList<>();
        JsonRootBean root = JSON.parseObject(result,JsonRootBean.class);
        CollectionUtils.emptyIfNull(root.getData().getResult()).forEach(x->{
            CollectionUtils.emptyIfNull(x.getValues()).forEach(m->{
                LogLine log = new LogLine();
                log.setValue(m[1]);
                String value = m[1];
                lines.add(value);
            });
        });
        dealLogLine(lines);
    }

    private static void dealLogLine(List<String> loginfo){
        List<LogLine> logs = new ArrayList<>();
        CollectionUtils.emptyIfNull(loginfo).forEach(x->{
            LogLine log = new LogLine();
            String value = x;
            String time = StringUtils.substringAfter(value,"[v1] [");
            time = StringUtils.substringBefore(time,"]");
            log.setTime(time);
            String detail = StringUtils.substringAfterLast(value,"feign-call:");
            String[] splits = StringUtils.split(detail, StringPool.COMMA);
            String caller = splits[0];
            String clazz = splits[2];
            String method = splits[3];
            String uri = splits[4];
            log.setCaller(caller);
            log.setClazz(clazz);
            log.setMethod(method);
            log.setUri(uri);
            logs.add(log);
        });

        log.info(JSON.toJSONString(logs));
        List<String> lines = new ArrayList<>();
        CollectionUtils.emptyIfNull(logs).forEach(x->{
            String line = StringUtils.joinWith(StringPool.COMMA,x.getTime(),x.getCaller(),x.getClazz(),x.getMethod(),x.getUri());
            lines.add(line);
        });
        File file = new File("/Users/liuwei19/Samsung/gitcode/workplace/dsc/caller.csv");
        FileUtil.appendLines(lines,file, StandardCharsets.UTF_8);
    }

    @lombok.Data
    public static class LogLine{
        private String time;
        private String value;
        private String caller;
        private String clazz;
        private String method;
        private String uri;
    }

    private static String search(String env, String app, String keywords, String start, String end) throws Exception {
        String demo =
                """
                {env="prod", app="factory-dsc-logistics-searcher", pod_ip=~".*"} |= "feign-call"
                https://log.ops.lixiangoa.com/api/datasources/proxy/1/loki/api/v1/query_range?direction=BACKWARD&limit=5000&query=%7Benv%3D%22prod%22%2C%20app%3D%22factory-dsc-logistics-searcher%22%2C%20pod_ip%3D~%22.*%22%7D%20%7C%3D%20%22feign-call%22&start=1711864311638000000&end=1714456311638000000&step=3600
                """;
        String template =
                """
                {env="{}", app="{}", pod_ip=~".*"} |= "{}"
                """;
        String source = """
                %7Benv%3D%22prod%22%2C%20app%3D%22factory-dsc-logistics-searcher%22%2C%20pod_ip%3D~%22.*%22%7D%20%7C%3D%20%22feign-call%22
                """;
        String query = URLEncoder.encode(StrUtil.format(template,env,app,keywords), Charset.defaultCharset());
        //String url = StrUtil.format(uri,source,start,end);
        String url = """
                https://log.ops.lixiangoa.com/api/datasources/proxy/1/loki/api/v1/query_range?direction=BACKWARD&limit=500&query=%7Benv%3D%22prod%22%2C%20app%3D%22factory-dsc-logistics-searcher%22%2C%20pod_ip%3D~%22.*%22%7D%20%7C%3D%20%22feign-call%22&start=1711864311638000000&end=1714456311638000000&step=3600
                """;
        url = StringUtils.replace(url,"1711864311638000000",end);
        url = StringUtils.replace(url,"1714456311638000000",start);
        log.info("start:{} end:{} url:{}", DateUtil.date(time2Data(Long.parseLong(start)/1000000)),DateUtil.date(time2Data(Long.parseLong(end)/1000000)),url);
        String result = get(url);
        log.info(result);
        JsonRootBean root = JSON.parseObject(result,JsonRootBean.class);
        return result;
    }

    private static Date time2Data(Long time){

        Timestamp timestamp = new Timestamp(time);
        Date date = new Date(timestamp.getTime());
        return date;
    }

    public static String get(String url) throws Exception {
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        // 设置请求类型
        con.setRequestMethod("GET");
        int responseCode = con.getResponseCode();
        System.out.println("Response Code : " + responseCode);
        // 读取响应
        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuilder response = new StringBuilder();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();
        // 打印结果
        return response.toString();
    }


    @lombok.Data
    public class JsonRootBean {
        private String status;
        private Data data;
    }

    @lombok.Data
    public class Data{
        List<Result> result;
    }

    @lombok.Data
    public class Result{
        List<String[]> values;
    }

}

